package org.jordens.jdbcspy.testutil.callbacks;

import org.jordens.jdbcspy.jmx.*;
import org.testng.*;

import java.io.*;

/**
 * An example JDBCSpyListenerCallback implementation that provides output as
 * a basic HTML report.
 *
 * The report will track the following on a per-testcase basis:
 * - overall test time
 * - time spent executing sql
 * - # of sql queries executed
 *
 * @author Adam Jordens
 */
public class HTMLOutputJDBCSpyListenerCallback implements JDBCSpyListenerCallback
{
    private final String passColor;
    private final String failColor;
    private final BufferedWriter writer;

    // if a test case takes longer than 'testTimeCutoff', it will be considered failed
    private final int testTimeCutoff = 500;

    // if a test case executes more than 'numberOfQueriesCutoff' SQL queries, it will be considered failed
    private final int numberOfQueriesCutoff = 100;

    // if a test case spends more than 'executionCutoff' of its time executing sql (and the total test time was > 'testTimeCutoff'), it will be considered failed
    private final double executionCutoff = 0.3d;

    // if a test case spends more than 'percentageCutoff' of its time executing sql, it will be considered failed
    private final double percentageCutoff = 30.0d;
    
    private long lastNumberOfQueriesExecutedCount = 0;
    private long lastSQLExecutionTime = 0;

    /**
     * @param outputFile Destination file for html report
     * @param passColor HTML color code that will be used for pass conditions
     * @param failColor HTML color code that will be used for failure conditions
     */
    public HTMLOutputJDBCSpyListenerCallback(File outputFile, String passColor, String failColor)
    {
        try
        {
            writer = new BufferedWriter(new FileWriter(outputFile));
        }
        catch (IOException e)
        {
            throw new IllegalArgumentException(e);
        }

        if (passColor == null)
        {
            throw new NullPointerException("passColor must not be null");
        }

        if (failColor == null)
        {
            throw new NullPointerException("failColor must not be null");
        }

        this.passColor = passColor;
        this.failColor = failColor;
    }

    /**
     * {@inheritDoc}
     */
    public void onSuiteStart()
    {
        writeLine("<html>");
        writeLine("<header><title>JDBCSpyListener Output</title></header>");
        writeLine("<body>");
        writeLine("<table border=0>");
        writeLine("<tr><th>Test Name</th><th>Test Time(ms)</th><th>SQL Execution Time(ms)</th><th></th><th># of SQL Queries Executed</th></tr>");
    }

    /**
     * {@inheritDoc}
     */
    public void onStart(JDBCSpyMBean jdbcSpy, ITestResult testResult)
    {
        this.lastNumberOfQueriesExecutedCount = jdbcSpy.getNumberOfQueriesExecuted();
        this.lastSQLExecutionTime = jdbcSpy.getSQLExecutionTime();
    }

    /**
     * {@inheritDoc}
     */
    public void onFinish(JDBCSpyMBean jdbcSpy, ITestResult testResult)
    {
        long currentNumberOfQueriesExecutedCount = jdbcSpy.getNumberOfQueriesExecuted();
        long currentSQLExecutionTime = jdbcSpy.getSQLExecutionTime();

        String testBackground = passColor;
        long testTime = testResult.getEndMillis() - testResult.getStartMillis();
        if (testTime > testTimeCutoff)
        {
            testBackground = failColor;
        }

        String sqlBackground = passColor;
        Long numberOfQueries = currentNumberOfQueriesExecutedCount - lastNumberOfQueriesExecutedCount;
        if (numberOfQueries > numberOfQueriesCutoff)
        {
            sqlBackground = failColor;
        }

        String executionBackground = passColor;
        long sqlExecutionTime = currentSQLExecutionTime - lastSQLExecutionTime;
        if (((double) sqlExecutionTime / testTime) > executionCutoff && testTime > testTimeCutoff)
        {
            executionBackground = failColor;
        }

        String percentageBackground = passColor;
        double percentage = Math.round(((double) sqlExecutionTime / testTime) * 100);
        if (percentage > percentageCutoff)
        {
            percentageBackground = failColor;
        }

        writeLine("<tr><td>" + testResult.getName() + "</td>" +
                "<td bgcolor=" + testBackground + ">" + testTime + "</td>" +
                "<td bgcolor=" + executionBackground + ">" + sqlExecutionTime + "</td>" +
                "<td bgcolor=" + percentageBackground + ">" + percentage + "%</td>" +
                "<td bgcolor=" + sqlBackground + ">" + numberOfQueries + "</td>" +
                "</tr>");
    }

    /**
     * {@inheritDoc}
     */
    public void onSuiteFinish()
    {
        writeLine("</table>");
        writeLine("</body>");
        writeLine("</html>");

        try
        {
            writer.close();
        }
        catch (Exception e)
        {
            throw new IllegalStateException(e);
        }
    }

    /**
     * @param line String to be written to current 'writer', \n will be appended.
     */
    private void writeLine(String line)
    {
        try
        {
            writer.write(line + "\n");
        }
        catch (IOException e)
        {
            throw new IllegalStateException(e);
        }

    }
}
